#include "stdafx.h"
#include "DBFFileProcessor.h"
#include "DateTime.h"

DBFFileProcessor::DBFFileProcessor(CircleDequeueBase* p_pcCircleQueue,
				   const unsigned int p_uiInterval, 
				   string p_strFilePath, 
				   const unsigned int p_uiBufferSize,
				   bool p_bVerifyLocalTime,
				   unsigned int p_uiFileType)
:FileBase(p_strFilePath,p_uiBufferSize)
,m_pcCircleQueue(p_pcCircleQueue)
,m_uiInterval(p_uiInterval)
,m_bVerifyLocalTime(p_bVerifyLocalTime)
,m_uiFileType(p_uiFileType)
{
	memset(m_szLastDBFDate,0,8);
}

bool DBFFileProcessor::Process()
{
	//LOG(INFO) << "Start to process file " << m_uiFileType; // for test

	// Read from file
	if(false == FileBase::OpenFile())
	{
		LOG(ERROR) << "Open file error. File type : " << m_uiFileType;
		return false;
	}

	// Verify file if it is valid
	if (false == VerifyFile())
	{
		return false;
	}

	// Process data
	if (m_uiFileLength > 0 && (NULL != m_pszBuffer))
	{
		// Get DBF time and local time
		DbfHeadNew* pstDBFHead = (DbfHeadNew*)m_pszBuffer;
		FieldElement* pstField = (FieldElement*)(m_pszBuffer + sizeof(DbfHeadNew));
		Time stDBFTime;
		FileBase::GetDBFTime(stDBFTime,m_uiFileType);
		Time stDBFDate;
		FileBase::GetDBFDate(stDBFDate,m_uiFileType);
		string strLocalDate = DateTime::GetLocalDate();

		// Compare DBF time with local time
		if (memcmp(stDBFDate.szTime,strLocalDate.data(),8) != 0)
		{
			LOG(ERROR) << "DBF time is dismatch with local time. File type : " << m_uiFileType;
			return false;
		}

		// Get last DBF buffer
		char* szLastDBFBuffer = NULL;
		unsigned int uiLastBufferLength = m_pcCircleQueue->GetEntireBuffer(&szLastDBFBuffer);

		//DbfHeadNew* pstLastDBFHead = (DbfHeadNew*)szLastDBFBuffer;
		if (memcmp(m_szLastDBFDate,stDBFDate.szTime,8) != 0) // Last DBF and new DBF file date is dismatch
		{
			// Write to circle queue
			LOG(INFO) << "Last dbf date is not same with current dbf date. File type : " << m_uiFileType;
			m_pcCircleQueue->SetEntireFlag();
			m_pcCircleQueue->WriteData(m_pszBuffer, m_uiFileLength);
			memcpy(m_szLastDBFDate,stDBFDate.szTime,8);
		}
		else if ((uiLastBufferLength != m_uiFileLength) || memcmp(szLastDBFBuffer,m_pszBuffer,m_uiFileLength) != 0) // Last DBF and new DBF data buffer are same
		{
			// Write to circle queue
			m_pcCircleQueue->WriteData(m_pszBuffer, m_uiFileLength);
		}
	}

	return true;
}

bool DBFFileProcessor::VerifyFile()
{
	// Get current local time
	string strLocalDate = DateTime::GetLocalDate();

	// Verify DBF length
	if (m_uiFileLength < sizeof(DbfHeadNew))
	{
		LOG(ERROR) << " File length less than " << sizeof(DbfHeadNew) << ". Cannot be loaded";
		return false;
	}

	DbfHeadNew* DbfHead = (DbfHeadNew*)m_pszBuffer;
	unsigned int uiDbfLength = DbfHead->m_usHeadLength + DbfHead->m_ulRecordNumber * DbfHead->m_usRecordLength;
	if (uiDbfLength < m_uiFileLength)
	{
		m_uiFileLength = uiDbfLength;
	}

	// Verify different kind of file type
	char szDBFDate[8];
	memset(szDBFDate,0,8);
	if (m_uiFileType == FILETYPE_SHOW) // Make an exception for show file
	{
		FieldElement* pstField = (FieldElement*)(m_pszBuffer + sizeof(DbfHeadNew));
		memcpy(szDBFDate,m_pszBuffer + DbfHead->m_usHeadLength + pstField[5].m_ulOffset,8);
		if (memcmp(m_szLastDBFDate,strLocalDate.data(),8) != 0 && memcmp(szDBFDate,strLocalDate.data(),8) == 0)
		{
			LOG(INFO) << "First reading after initialize. File Type : " << m_uiFileType;;
			//FileBase::CloseFile();
			// Wait for DBF initialize
			WaitForDBFFileInit();
		}
	}
	else if (m_uiFileType == FILETYPE_SJSHQ || 
			 m_uiFileType == FILETYPE_STBHQ || 
			 m_uiFileType == FILETYPE_SJSXX || 
			 m_uiFileType == FILETYPE_HGHQ || 
			 m_uiFileType == FILETYPE_HGXXN)
	{
		FieldElement* pstField = (FieldElement*)(m_pszBuffer + sizeof(DbfHeadNew));
		memcpy(szDBFDate,m_pszBuffer + DbfHead->m_usHeadLength + pstField[1].m_ulOffset,8);
		if (memcmp(m_szLastDBFDate,strLocalDate.data(),8) != 0 && memcmp(szDBFDate,strLocalDate.data(),8) == 0)
		{
			LOG(INFO) << "First reading after initialize. FileType : " << m_uiFileType;
			if (m_uiFileType == FILETYPE_SJSXX || m_uiFileType == FILETYPE_HGXXN)
			{
				Sleep(2000);
			}
			else
			{
				//FileBase::CloseFile();
				// Wait for DBF initialize
				WaitForDBFFileInit();
			}
		}
	}
	else if (m_uiFileType == FILETYPE_GZLX)
	{
		FieldElement* pstField = (FieldElement*)(m_pszBuffer + sizeof(DbfHeadNew));
		memcpy(szDBFDate,m_pszBuffer + DbfHead->m_usHeadLength + pstField[1].m_ulOffset,8);
		if (memcmp(m_szLastDBFDate,strLocalDate.data(),8) != 0 && memcmp(szDBFDate,strLocalDate.data(),8) == 0)
		{
			LOG(INFO) << "First reading after initialize. File Type : " << m_uiFileType;;
		}
	}

	// Close file
	if(false == FileBase::CloseFile())
	{
		LOG(ERROR) << "Close file error";
		return false;
	}

	return true;
}

void DBFFileProcessor::WaitForDBFFileInit()
{
	while(1)
	{
		if (NULL != m_pszBuffer && m_uiFileLength <= sizeof(DbfHeadNew) + sizeof(FieldElement))
		{
			Sleep(2000);
			FileBase::CloseFile();
			FileBase::OpenFile();
			continue;
		}

		DbfHeadNew* pstDBFHead = (DbfHeadNew*)m_pszBuffer;
		FieldElement* pstField = (FieldElement*)(m_pszBuffer + sizeof(DbfHeadNew));
		if (pstDBFHead->m_ulRecordNumber <= 0)
		{
			Sleep(2000);
			FileBase::CloseFile();
			FileBase::OpenFile();
			continue;
		}

		// [TODO]GetUnchangedStock()
		break;
	}
}